Subject: Re: RKRM Libraries mystery: child task and library pointers
From: [email-masked] (Todd M. Lewis)
Date: 18 Mar 1994 15:32:42 GMT
Newsgroups: comp.sys.amiga.programmer

In article <[email-masked]> [email-masked] (Harri  
I Poyhonen) writes:
>[...]RKRM doesn't
>explicitly state *why* library bases shouldn't be shared, guess it has
>something to do with library data area integrity.

superb guessing on your part.  Actually, it could be lots of other
reasons.  If the library isn't documented as being sharable, then
you can only guess, and sooner or later you will guess wrong.

>This raises following questions: Can I go on sharing the library pointers? 

Yes.

>Safely?

No.  At least not without some more precautions.

>If I make sure that the library is used by at most one task at a time?

Not relevant.

>What are the library bases that must *not* be shared?

Unbounded set.  Only libraries documented as sharable are sharable.
That list is much smaller.  However, consider that BOOPSI methods
get called from Intuition's context.  Therefore anything that gets
done by a BOOPSI method had better be done by dedicated code or by
a sharable library.

The rule to follow is that each using task/process _must_ open and
close the libraries it uses.  Now, IF you do that, AND IF the base
value returned by the OpenLibrary() call in each of your tasks
just happens to be the same for a given library, then you can use
the same global variable to hold the library base pointer for all 
your tasks.  If in the future one of these libraries changes on
you and no longer uses the same base for each opener then you
need to handle that gracefully.  The code below handles that.
Use and enjoy

/*
 * Call OpenSharableBaseLibrary() to open libraries
 * whose bases must be shared among tasks.  It fails (returns NULL)
 * if the library can't be opened or if the base value returned
 * is not the same as the value the rest of the tasks are using.
 *   The 3rd parameter is a pointer to your global base pointer
 * for the library in question.  DO NOT assign the return value
 * to your global base pointer--the routine does that if it should,
 * and if the library were previously opened and this open failed
 * you would wipe out the global variable that other tasks were
 * using.
 */
struct Library *OpenSharableBaseLibrary( char *libname, 
                                         LONG ver, 
					 struct Library **base )
{
  struct Library *tmpbase;
  
  tmpbase = OpenLibrary( libname, ver );

  if ( (*base == NULL)  || ( *base == tmpbase )  )
        *base = tmpbase;
    else
      {
        if ( tmpbase )
	  CloseLibrary( tmpbase );
	tmpbase = NULL;
      }
  return tmpbase;
}

/*--------------------------------------------------------------------*/
/* Example use in a subtask.  Note that the return value is NOT
 * assigned to the global base pointer.  Note also that
 * every successful open is paired with a close from within the same
 * task.
 *   When closing the library, you cannot assume that a non-NULL global
 * base pointer implies that your task's Open...() was sucessful.  That
 * value may have been supplied by other tasks which may be using the
 * pointer.  You will need some other mechanism to determine whether
 * to close a given library.  (In this example we use the fact that
 * we are in the if()... statement block.)
 */
if ( OpenSharableBaseLibrary( "intuition.library", 0L, &IntuitionBase ) )
  {
    if ( OpenSharableBaseLibrary( "gorp.library", 0L, &GorpBase ) )
      {
        do_neat_task_stuff();
        CloseLibrary( GorpBase );
      }
     else
        task_error( ERROR_LIB_BASE_NOT_SHARABLE, "gorp.library" );
    CloseLibrary( IntuitionBase );
  }
 else
    task_error( ERROR_LIB_BASE_NOT_SHARABLE, "intuition.library" );

--
[email-masked]   ASDF - Amiga Software Developers Forum
               "Where the Pizza Meets the Code"